package org.go.scheduler;

import java.io.Serializable;
import java.util.ArrayList;
import java.util.List;

import org.go.domain.GoDomain;
import org.go.plugin.GoPlugin;
import org.go.scheduler.database.JobRunShellFactory;
import org.go.threadpool.GoThreadPool;
import org.go.work.Work;
import org.go.work.WorkRunShellFactory;
import org.go.workstore.WorkStore;

/**
 * 
 * @author hejie
 *
 */
public class SchedulerResources implements Serializable {
	/**
	 * 
	 */
	private static final long serialVersionUID = -5402889862040348305L;

	public static String generateJMXObjectName(String schedName, String schedInstId) {
		return "Go:type=GoScheduler" + ",name=" + schedName.replaceAll(":|=|\n", ".") + ",instance=" + schedInstId;
	}

	public static String getUniqueIdentifier(String schedName, String schedInstId) {
		//DEFAULT_SCHEDULER_NAME, DEFAULT_INSTANCE_ID
		if (null == schedInstId || "".equals(schedInstId)) {
			schedInstId = GoDomain.DEFAULT_INSTANCE_ID;
		}
		return schedName + "_$_" + schedInstId;
	}

	private long batchTimeWindow;

	private String instanceId;

	private boolean interruptJobsOnShutdown = false;

	private boolean interruptJobsOnShutdownWithWait = false;

	private boolean jmxExport;

	private String jmxObjectName;

	private WorkRunShellFactory jobRunShellFactory;

	private boolean makeSchedulerThreadDaemon = false;

	private int maxBatchSize;

	private String name;

	private GoThreadPool pool = null;

	private String rmiBindName;

	private String rmiCreateRegistryStrategy = GoDomain.CREATE_REGISTRY_NEVER;

	private String rmiRegistryHost = null;

	private int rmiRegistryPort = 1099;

	private int rmiServerPort = -1;

	private boolean runUpdateCheck = true;

	private List<GoPlugin> schedulerPlugins = new ArrayList<GoPlugin>(10);

	private String threadName;

	private boolean threadsInheritInitializersClassLoadContext = false;

	private WorkStore workerStore;

	/**
	 * <p>
	 * Create an instance with no properties initialized.
	 * </p>
	 */
	public SchedulerResources() {
		// do nothing...
	}

	public void addGoPool(GoThreadPool arg) {
		if (arg == null) {
			throw new IllegalArgumentException("ThreadPool cannot be null.");
		}
		this.pool = arg;
	}

	/**
	 * <p>
	 * Add the given <code>{@link org.quartz.spi.SchedulerPlugin}</code> for the 
	 * <code>{@link QuartzScheduler}</code> to use. This method expects the plugin's
	 * "initialize" method to be invoked externally (either before or after
	 * this method is called).
	 * </p>
	 */
	public void addSchedulerPlugin(GoPlugin plugin) {
		schedulerPlugins.add(plugin);
	}

	public void addWorkerDesc(Work workerDesc) {
		workerStore.addWorkDesc(workerDesc);
	}

	public void addWorkerStore(WorkStore arg) {
		workerStore = arg;
	}

	public long getBatchTimeWindow() {
		return batchTimeWindow;
	}

	/**
	 * <p>
	 * Get the instance Id for the <code>{@link QuartzScheduler}</code>.
	 * </p>
	 */
	public String getInstanceId() {
		return instanceId;
	}

	/**
	 * Get whether the QuartzScheduler should be registered with the local 
	 * MBeanServer.
	 */
	public boolean getJMXExport() {
		return jmxExport;
	}

	/**
	 * Get the name under which the QuartzScheduler should be registered with 
	 * the local MBeanServer.  If unset, defaults to the value calculated by 
	 * <code>generateJMXObjectName<code>.
	 * 
	 * @see #generateJMXObjectName(String, String)
	 */
	public String getJMXObjectName() {
		return (jmxObjectName == null) ? generateJMXObjectName(name, instanceId) : jmxObjectName;
	}

	/**
	 * <p>
	 * Get the <code>{@link JobRunShellFactory}</code> for the <code>{@link QuartzScheduler}</code>
	 * to use.
	 * </p>
	 */
	public WorkRunShellFactory getJobRunShellFactory() {
		return jobRunShellFactory;
	}

	/**
	 * Get whether to mark the Quartz scheduling thread as daemon.
	 * 
	 * @see Thread#setDaemon(boolean)
	 */
	public boolean getMakeSchedulerThreadDaemon() {
		return makeSchedulerThreadDaemon;
	}

	public int getMaxBatchSize() {
		return maxBatchSize;
	}

	/**
	 * <p>
	 * Get the name for the <code>{@link GoScheduler}</code>.
	 * </p>
	 */
	public String getName() {
		return name;
	}

	public GoThreadPool getPool() {
		return pool;
	}

	/**
	 * Get the name under which to bind the QuartzScheduler in RMI.  Will 
	 * return the value of the uniqueIdentifier property if explict RMI bind 
	 * name was never set.
	 * 
	 * @see #getUniqueIdentifier()
	 */
	public String getRMIBindName() {
		return (rmiBindName == null) ? getUniqueIdentifier() : rmiBindName;
	}

	/**
	 * <p>
	 * Get the setting of whether or not Quartz should create an RMI Registry,
	 * and if so, how.
	 * </p>
	 */
	public String getRMICreateRegistryStrategy() {
		return rmiCreateRegistryStrategy;
	}

	/**
	 * <p>
	 * Get the host name of the RMI Registry that the scheduler should export
	 * itself to.
	 * </p>
	 */
	public String getRMIRegistryHost() {
		return rmiRegistryHost;
	}

	/**
	 * <p>
	 * Get the port number of the RMI Registry that the scheduler should export
	 * itself to.
	 * </p>
	 */
	public int getRMIRegistryPort() {
		return rmiRegistryPort;
	}

	/**
	 * <p>
	 * Get the port number the scheduler server will be bound to.
	 * </p>
	 */
	public int getRMIServerPort() {
		return rmiServerPort;
	}

	public List<GoPlugin> getSchedulerPlugins() {
		return schedulerPlugins;
	}

	/**
	 * <p>
	 * Get the name for the <code>{@link QuartzSchedulerThread}</code>.
	 * </p>
	 */
	public String getThreadName() {
		return threadName;
	}

	public String getUniqueIdentifier() {
		return getUniqueIdentifier(name, instanceId);
	}

	public WorkStore getWorkerStore() {
		return workerStore;
	}

	public boolean isInterruptJobsOnShutdown() {
		return interruptJobsOnShutdown;
	}

	public boolean isInterruptJobsOnShutdownWithWait() {
		return interruptJobsOnShutdownWithWait;
	}

	public boolean isRunUpdateCheck() {
		return runUpdateCheck;
	}

	/**
	 * Get whether to set the class load context of spawned threads to that
	 * of the initializing thread.
	 */
	public boolean isThreadsInheritInitializersClassLoadContext() {
		return threadsInheritInitializersClassLoadContext;
	}

	/**
	 * <p>
	 * Set the <code>{@link JobRunShellFactory}</code> for the <code>{@link QuartzScheduler}</code>
	 * to use.
	 * </p>
	 * 
	 * @exception IllegalArgumentException
	 *              if jobRunShellFactory is null.
	 */

	/**
	 * <p>
	 * Set the <code>{@link workerStore}</code> for the <code>{@link QuartzScheduler}</code>
	 * to use.
	 * </p>
	 * 
	 * @exception IllegalArgumentException
	 *              if workerStore is null.
	 */

	public Work queryWorkerDesc(String workerId) {
		return workerStore.queryWorkDesc(workerId);
	}

	public void setBatchTimeWindow(long batchTimeWindow) {
		this.batchTimeWindow = batchTimeWindow;
	}

	/**
	 * <p>
	 * Set the name for the <code>{@link QuartzScheduler}</code>.
	 * </p>
	 * 
	 * @exception IllegalArgumentException
	 *              if name is null or empty.
	 */
	public void setInstanceId(String instanceId) {
		if (instanceId == null || instanceId.trim().length() == 0) {
			throw new IllegalArgumentException("Scheduler instanceId cannot be empty.");
		}

		this.instanceId = instanceId;
	}

	public void setInterruptJobsOnShutdown(boolean interruptJobsOnShutdown) {
		this.interruptJobsOnShutdown = interruptJobsOnShutdown;
	}

	public void setInterruptJobsOnShutdownWithWait(boolean interruptJobsOnShutdownWithWait) {
		this.interruptJobsOnShutdownWithWait = interruptJobsOnShutdownWithWait;
	}

	/**
	 * Set whether the QuartzScheduler should be registered with the local 
	 * MBeanServer.
	 */
	public void setJMXExport(boolean jmxExport) {
		this.jmxExport = jmxExport;
	}

	/**
	 * Set the name under which the QuartzScheduler should be registered with 
	 * the local MBeanServer.  If unset, defaults to the value calculated by 
	 * <code>generateJMXObjectName<code>.
	 * 
	 * @see #generateJMXObjectName(String, String)
	 */
	public void setJMXObjectName(String jmxObjectName) {
		this.jmxObjectName = jmxObjectName;
	}

	/**
	 * Set whether to mark the Quartz scheduling thread as daemon.
	 * 
	 * @see Thread#setDaemon(boolean)
	 */
	public void setMakeSchedulerThreadDaemon(boolean makeSchedulerThreadDaemon) {
		this.makeSchedulerThreadDaemon = makeSchedulerThreadDaemon;
	}

	public void setMaxBatchSize(int maxBatchSize) {
		this.maxBatchSize = maxBatchSize;
	}

	/**
	 * <p>
	 * Set the name for the <code>{@link QuartzScheduler}</code>.
	 * </p>
	 * 
	 * @exception IllegalArgumentException
	 *              if name is null or empty.
	 */
	public void setName(String name) {
		if (name == null || name.trim().length() == 0) {
			throw new IllegalArgumentException("Scheduler name cannot be empty.");
		}

		this.name = name;

		if (threadName == null) {
			// thread name not already set, use default thread name
			setThreadName(name + "_QuartzSchedulerThread");
		}
	}

	/**
	 * Set the name under which to bind the QuartzScheduler in RMI.  If unset, 
	 * defaults to the value of the uniqueIdentifier property.
	 * 
	 * @see #getUniqueIdentifier()
	 */
	public void setRMIBindName(String rmiBindName) {
		this.rmiBindName = rmiBindName;
	}

	/**
	 * <p>
	 * Set whether or not Quartz should create an RMI Registry, and if so, how.
	 * </p>
	 * 
	 * @see #CREATE_REGISTRY_ALWAYS
	 * @see #CREATE_REGISTRY_AS_NEEDED
	 * @see #CREATE_REGISTRY_NEVER
	 */
	public void setRMICreateRegistryStrategy(String rmiCreateRegistryStrategy) {
		if (rmiCreateRegistryStrategy == null || rmiCreateRegistryStrategy.trim().length() == 0) {
			rmiCreateRegistryStrategy = GoDomain.CREATE_REGISTRY_NEVER;
		} else if (rmiCreateRegistryStrategy.equalsIgnoreCase("true")) {
			rmiCreateRegistryStrategy = GoDomain.CREATE_REGISTRY_AS_NEEDED;
		} else if (rmiCreateRegistryStrategy.equalsIgnoreCase("false")) {
			rmiCreateRegistryStrategy = GoDomain.CREATE_REGISTRY_NEVER;
		} else if (rmiCreateRegistryStrategy.equalsIgnoreCase(GoDomain.CREATE_REGISTRY_ALWAYS)) {
			rmiCreateRegistryStrategy = GoDomain.CREATE_REGISTRY_ALWAYS;
		} else if (rmiCreateRegistryStrategy.equalsIgnoreCase(GoDomain.CREATE_REGISTRY_AS_NEEDED)) {
			rmiCreateRegistryStrategy = GoDomain.CREATE_REGISTRY_AS_NEEDED;
		} else if (rmiCreateRegistryStrategy.equalsIgnoreCase(GoDomain.CREATE_REGISTRY_NEVER)) {
			rmiCreateRegistryStrategy = GoDomain.CREATE_REGISTRY_NEVER;
		} else {
			throw new IllegalArgumentException("Faild to set RMICreateRegistryStrategy - strategy unknown: '" + rmiCreateRegistryStrategy + "'");
		}

		this.rmiCreateRegistryStrategy = rmiCreateRegistryStrategy;
	}

	/**
	 * <p>
	 * Set the host name of the RMI Registry that the scheduler should export
	 * itself to.
	 * </p>
	 */
	public void setRMIRegistryHost(String hostName) {
		this.rmiRegistryHost = hostName;
	}

	/**
	 * <p>
	 * Set the port number of the RMI Registry that the scheduler should export
	 * itself to.
	 * </p>
	 */
	public void setRMIRegistryPort(int port) {
		this.rmiRegistryPort = port;
	}

	/**
	 * <p>
	 * Set the port number the scheduler server will be bound to.
	 * </p>
	 */
	public void setRMIServerPort(int port) {
		this.rmiServerPort = port;
	}

	public void setRunUpdateCheck(boolean runUpdateCheck) {
		this.runUpdateCheck = runUpdateCheck;
	}

	/**
	 * <p>
	 * Set the name for the <code>{@link QuartzSchedulerThread}</code>.
	 * </p>
	 * 
	 * @exception IllegalArgumentException
	 *              if name is null or empty.
	 */
	public void setThreadName(String threadName) {
		if (threadName == null || threadName.trim().length() == 0) {
			throw new IllegalArgumentException("Scheduler thread name cannot be empty.");
		}

		this.threadName = threadName;
	}

	/**
	 * Set whether to set the class load context of spawned threads to that
	 * of the initializing thread.
	 */
	public void setThreadsInheritInitializersClassLoadContext(boolean threadsInheritInitializersClassLoadContext) {
		this.threadsInheritInitializersClassLoadContext = threadsInheritInitializersClassLoadContext;
	}

	public void setWorkerStore(WorkStore workerStore) {
		this.workerStore = workerStore;
	}
}
